package gld.algo.park;

import gld.infra.Drivelane;
import gld.infra.InfraException;
import gld.infra.Road;

import java.util.*;

public class StageConfig {

	Intersection intersection;

	HashSet<Stage> possibleStages;
	
	LinkedList<Stage> orderedPossibleStages;

	public StageConfig(Intersection i) {
		intersection = i;
	}

	/**
	 * Returns a set of stages.
	 * Each stage contains a set of drivelanes that can turn green at the same time
	 * @return
	 * @throws InfraException 
	 */
	public HashSet<Stage> getPossibleStages() throws InfraException {
		if (possibleStages != null)
			return possibleStages;
		
		possibleStages = new HashSet<Stage>();
		// Begin calculating possible stages.
		// Currently only return stages that have opposing roads set to green
		LinkedList<HashSet<Road>> opposingRoads = getIntersection().getJunction()
				.getOpposingRoads();
		// Assign lanes in opposing roads turn green in the same stages
		for(HashSet<Road> roads : opposingRoads) {
			HashSet<Drivelane> lanesHavingSameStage = new HashSet<Drivelane>();
			for (Road road:roads) {
				for (Drivelane lane : road.getInboundLanes(getIntersection().getJunction()))
					lanesHavingSameStage.add(lane);
			}
			// Because opposing roads may not have inbound lanes for this junction,
			// check first if it's empty
			if (lanesHavingSameStage.size() > 0) {
				Stage s = new Stage(lanesHavingSameStage, intersection);
				possibleStages.add(s);
			}
		}
		return possibleStages;		
	}
	
	/**
	 * Order the stages from getPossibleStages
	 * @return A list of stages
	 * @throws InfraException 
	 */
	public LinkedList<Stage> getOrderedPossibleStages() throws InfraException {
		if (orderedPossibleStages != null)
			return orderedPossibleStages;
		
		orderedPossibleStages = new LinkedList<Stage>();
		for (Stage stage : getPossibleStages())
			orderedPossibleStages.add(stage);
		return orderedPossibleStages;
	}
	

	public Intersection getIntersection() {
		return intersection;
	}
}
